<?php

namespace JLPay\Models\Upload;

use JLPay\Models\BaseRequest;
use JLPay\Exceptions\ConfigException;
use JLPay\Utils\SmUtils;

/**
 * 文件上传请求基类
 */
abstract class FileUploadRequest extends BaseRequest
{
    /**
     * 文件内容
     * @var resource|string
     */
    protected $file;
    
    /**
     * 文件名
     * @var string
     */
    protected $fileName;
    
    /**
     * 元数据
     * @var string
     */
    protected $meta;

    /**
     * 设置文件内容
     *
     * @param resource|string $file 文件内容
     * @param string $fileName 文件名
     * @return self
     */
    public function setFile($file, string $fileName): self
    {
        $this->file = $file;
        $this->fileName = $fileName;
        return $this;
    }

    /**
     * 从文件路径设置文件
     *
     * @param string $filePath 文件路径
     * @return self
     * @throws ConfigException
     */
    public function setFileFromPath(string $filePath): self
    {
        if (!file_exists($filePath)) {
            throw new ConfigException("文件不存在: {$filePath}");
        }
        
        $this->file = fopen($filePath, 'rb');
        $this->fileName = basename($filePath);
        return $this;
    }

    /**
     * 设置元数据
     *
     * @param array $meta 元数据数组
     * @return self
     */
    public function setMeta(array $meta): self
    {
        $this->meta = json_encode($meta, JSON_UNESCAPED_UNICODE);
        return $this;
    }

    /**
     * 计算文件摘要并设置完整的元数据
     *
     * @param string $filename 文件名
     * @param string|null $fileContent 文件内容，如果为null则使用当前file属性
     * @return self
     */
    public function setMetaWithDigest(string $filename, ?string $fileContent = null): self
    {
        if ($fileContent === null) {
            if (is_resource($this->file)) {
                // 如果是文件资源，读取内容
                $currentPos = ftell($this->file);
                rewind($this->file);
                $fileContent = stream_get_contents($this->file);
                fseek($this->file, $currentPos);
            } elseif (is_string($this->file)) {
                $fileContent = $this->file;
            } else {
                throw new \InvalidArgumentException("无法获取文件内容用于计算摘要");
            }
        }

        // 计算SM3摘要
        $digest = SmUtils::getDigestByType('SM3', $fileContent);
        
        $meta = [
            'filename' => $filename,
            'alg' => 'SM3',
            'abstract' => $digest
        ];
        
        return $this->setMeta($meta);
    }

    /**
     * 获取文件内容
     *
     * @return resource|string
     */
    public function getFile()
    {
        return $this->file;
    }

    /**
     * 获取文件名
     *
     * @return string
     */
    public function getFileName(): string
    {
        return $this->fileName ?? '';
    }

    /**
     * 获取元数据
     *
     * @return string
     */
    public function getMeta(): string
    {
        return $this->meta ?? '{}';
    }
} 